项目源码：
    
 @Controller
public class sqlcontroller {

    @Autowired
    private UserService userService;

    @GetMapping("/sql")
    public String index(Model model, UserQuery userQuery){
        PageInfo<User> userPageInfo = userService.listUserByName(userQuery);
        model.addAttribute("page",userPageInfo);
        return "sql/sql";
    }

    @PostMapping("/sql")
    public String listUserByName(Model model,UserQuery userQuery){
        PageInfo<User> userPageInfo = userService.listUserByName(userQuery);
        model.addAttribute("page",userPageInfo);
        return "sql/sql";
    }
}


存在问题：
UserQuery 对象很可能包含了用户输入的查询参数，例如用于搜索用户姓名的字符串。如果这些参数直接拼接到SQL查询语句中，而没有经过适当的过滤或转义，攻击者可以通过输入特定的字符串来修改查询的结构，从而可能：
1.读取数据库中的敏感信息：通过构造特定的查询，攻击者可以访问到数据库中原本不应该公开的数据。
2.篡改、删除或添加数据：攻击者可以修改SQL语句，删除或更改数据库中的数据，或者插入新的恶意数据。
3.执行任意SQL代码：在某些情况下，攻击者甚至可以执行任意SQL语句，这可能会导致数据库被完全控制。

修改目的：
使用预编译语句（Prepared Statements）：预编译语句能够确保用户输入被当作数据来处理，而不是SQL代码的一部分。这样可以有效防止SQL注入攻击。
输入验证和过滤：验证用户输入是否满足预期的格式和长度，过滤掉任何可能导致SQL注入的特殊字符。
错误处理：不要将详细的数据库错误信息返回给用户。这可以防止攻击者利用这些信息进行进一步的攻击。
最小权限原则：数据库账号应该只拥有执行必要操作的最小权限。这样即使发生了SQL注入，攻击者也不能执行超出该权限范围的操作。

安全代码：

@Service
public class UserService {

    private final JdbcTemplate jdbcTemplate;

    public UserService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public PageInfo<User> listUserByName(UserQuery userQuery) {
        // 使用预编译的SQL语句和参数化查询
        String sql = "SELECT * FROM users WHERE name = :name LIMIT :offset, :limit";
        Map<String, Object> namedParameters = new HashMap<>();
        namedParameters.put("name", userQuery.getName());
        namedParameters.put("offset", userQuery.getOffset());
        namedParameters.put("limit", userQuery.getLimit());

        // 使用JdbcTemplate执行查询
        List<User> users = jdbcTemplate.query(sql, namedParameters, new UserRowMapper());

        // 转换用户列表为PageInfo对象
        return convertToPageInfo(users, userQuery.getPage(), userQuery.getSize());
    }

    // 实现UserRowMapper接口来转换ResultSet为User对象
    private static class UserRowMapper implements RowMapper<User> {
        @Override
        public User mapRow(ResultSet rs, int rowNum) throws SQLException {
            User user = new User();
            user.setId(rs.getLong("id"));
            user.setName(rs.getString("name"));
            // 设置其他属性
            return user;
        }
    }

    // 实现将用户列表转换为PageInfo对象的方法
    private PageInfo<User> convertToPageInfo(List<User> users, int page, int size) {
        // 实现分页逻辑
        return new PageInfo<>(users, page, size);
    }
}

